use rbs::Value;
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};

pub mod api;
pub mod app;
pub mod applog;
pub mod attend;
pub mod device;
pub mod log;
pub mod menu;
pub mod netpoint;
pub mod role;
pub mod user;

#[macro_export]
macro_rules! pool {
    () => {
        &mut $crate::utils::mysql::MYSQL.clone()
    };
}

fn serialize_json<T, S>(data: &T, serializer: S) -> Result<S::Ok, S::Error>
    where
        T: Serialize,
        S: Serializer,
{
    let json_str = serde_json::to_string(data).unwrap();
    serializer.serialize_str(&json_str)
}

fn deserialize_json<'de, T, D>(deserializer: D) -> Result<T, D::Error>
    where
        T: Deserialize<'de> + Default,
        D: Deserializer<'de>,
{
    let v: rbs::Value = Deserialize::deserialize(deserializer)?;
    match v {
        Value::Null => Ok(T::default()),
        Value::String(v) => {
            let value: serde_json::Value = serde_json::from_str(&v).map_err(de::Error::custom)?;
            T::deserialize(value).map_err(de::Error::custom)
        }
        Value::Binary(v) => {
            let value: serde_json::Value = serde_json::from_slice(&v).map_err(de::Error::custom)?;
            T::deserialize(value).map_err(de::Error::custom)
        }
        _ => Err(de::Error::custom("warn type")),
    }
}

fn deserialize_bool<'de, D>(deserializer: D) -> Result<bool, D::Error>
    where
        D: Deserializer<'de>,
{
    let v: rbs::Value = Deserialize::deserialize(deserializer)?;
    match v {
        Value::Bool(b) => Ok(b),
        Value::I32(v) => Ok(v > 0),
        Value::I64(v) => Ok(v > 0),
        Value::U32(v) => Ok(v > 0),
        Value::U64(v) => Ok(v > 0),
        Value::F32(v) => Ok(v > 0.0),
        Value::F64(v) => Ok(v > 0.0),
        _ => Err(de::Error::custom("warn type")),
    }
}

fn deserialize_option_bool<'de, D>(deserializer: D) -> Result<Option<bool>, D::Error>
    where
        D: Deserializer<'de>,
{
    let v: rbs::Value = Deserialize::deserialize(deserializer)?;
    match v {
        Value::Null => Ok(None),
        Value::Bool(b) => Ok(Some(b)),
        Value::I32(v) => Ok(Some(v > 0)),
        Value::I64(v) => Ok(Some(v > 0)),
        Value::U32(v) => Ok(Some(v > 0)),
        Value::U64(v) => Ok(Some(v > 0)),
        Value::F32(v) => Ok(Some(v > 0.0)),
        Value::F64(v) => Ok(Some(v > 0.0)),
        _ => Err(de::Error::custom("warn type")),
    }
}
